<script setup lang="ts">
import type { FolderProps, OpenParamProps, OptionProps } from '@/types';

import {
  type ComponentInternalInstance,
  computed,
  getCurrentInstance,
  ref,
} from 'vue';

import { Icon } from '@/components/core/icon';

import { ArrowRight } from '@element-plus/icons-vue';
import dayjs from 'dayjs';
import {
  type Action,
  ElBreadcrumb,
  ElBreadcrumbItem,
  ElButton,
  ElDialog,
  ElDivider,
  ElEmpty,
  ElInput,
  ElMessage,
  ElMessageBox,
} from 'element-plus';

import { formatFileSize, formatIcon, splitChar } from '@/utils';

defineOptions({
  name: 'SaveTo',
});
const emits = defineEmits(['confirm', 'cancel']);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const baseUrl = proxy?.$config.baseUrl;
const visible = ref(false);
const loading = ref(false);
const list = ref<FolderProps[]>([]);
const currentPath = ref('');
const checkName = ref('');
const openParam = ref<OpenParamProps>();
const breadcrumb = computed(() => {
  if (currentPath.value === splitChar) return [];
  const paths = currentPath.value?.split(splitChar).filter(Boolean) || [];
  const result: OptionProps[] = [];
  let path = '';

  paths.forEach((item) => {
    if (item) {
      path += `${splitChar}${item}`;
      result.push({ name: item, path });
    }
  });

  return result;
});

const loadFolder = (path: string) => {
  currentPath.value = path;
  loading.value = true;
  try {
    const url = `${baseUrl}/folder/list?path=${path}&filter=${openParam.value?.exts}`;
    fetch(url, {
      method: 'GET',
    })
      .then((response) => response.json())
      .then((res) => {
        const { code, data, msg } = res;
        if (code === 200 && data) {
          data.map((m: FolderProps) => {
            m.icon = formatIcon(m);
            m.parentPath = path;
            return m;
          });
          list.value = data as FolderProps[];
        } else {
          ElMessage.error(msg || '获取文件夹目录失败');
        }
      });
  } catch (error) {
    console.log(error);
    ElMessage.error('请求发生了错误，请稍后重试');
  } finally {
    loading.value = false;
  }
};

// 新建文件夹
const onNewFolder = () => {
  if (!currentPath.value) {
    ElMessage.warning('当前路径无法新建文件夹，请重试');
    return;
  }
  ElMessageBox.prompt('请输入文件夹名称', '新建文件夹', {
    buttonSize: 'small',
    cancelButtonText: '取消',
    confirmButtonText: '确定',
    customClass: 'wos-common-confirm',
    draggable: true,
    inputErrorMessage: '无效的名称，请重新输入',
    inputPattern: /^[^"%*/:<>?\\|]+$/,
    inputPlaceholder: '请输入新的文件或文件夹名称',
    inputValue: '新建文件夹',
  })
    .then(({ value }) => {
      loading.value = true;
      try {
        const postData = { name: value, path: currentPath.value };
        const url = `${baseUrl}/folder/newFolder`;
        fetch(url, {
          body: JSON.stringify(postData),
          headers: {
            'Content-Type': 'application/json;charset=utf-8',
          },
          method: 'POST',
        })
          .then((response) => response.json())
          .then((res) => {
            const { code, msg } = res;
            if (code === 200) {
              loadFolder(currentPath.value);
              ElMessage.success({
                message: msg || '新建文件夹成功',
                type: 'success',
              });
            } else {
              ElMessage.error(msg || '获取文件夹目录失败');
            }
          });
      } catch (error) {
        console.log(error);
        ElMessage.error('请求发生了错误，请稍后重试');
      } finally {
        loading.value = false;
      }
    })
    .catch(() => {
      console.log('取消');
    });
};
const onItemDbClick = (item: FolderProps) => {
  const { fullPath, type } = item;
  if (type === '1') return; // 文件不处理
  currentPath.value = fullPath || splitChar;
  loadFolder(fullPath);
};
async function checkFileName(fileName: string) {
  const checkPath = `${currentPath.value}${splitChar}${fileName}`;
  let result = { action: 'overwrite', fileName };
  // 检查是否存在同名文件
  const response = await fetch(`${baseUrl}/file/check?path=${checkPath}`, {
    method: 'GET',
  });
  const res = await response.json();
  const { code, data } = res;
  if (code === 200 && data) {
    result = await openConfirm(fileName); // 文件已存在
  }
  return result;
}
async function openConfirm(fileName: string) {
  const res = await ElMessageBox.prompt(
    '请输入新的文件名称',
    '文件已存在，是否覆盖保存文件？',
    {
      buttonSize: 'small',
      cancelButtonText: '覆盖并保存',
      closeOnClickModal: false,
      confirmButtonText: '保存',
      customClass: 'wos-common-confirm',
      draggable: true,
      inputErrorMessage: '无效的名称，请重新输入',
      inputPattern: /^[^"%*/:<>?\\|]+$/,
      inputPlaceholder: '请输入新的文件名称',
      inputValue: fileName,
    },
  )
    .then(async ({ value }) => {
      await checkFileName(value);
      return { action: 'overwrite', fileName: value };
    })
    .catch((error: Action) => {
      const _action = error === 'cancel' ? 'rename' : 'close';
      return { action: _action, fileName };
    });
  return res;
}
const onConfirm = async () => {
  let res = { action: 'overwrite', fileName: openParam.value?.checkName };
  if (openParam.value?.checkName) {
    if (!checkName.value) {
      ElMessage.warning('请输入文件名称');
      return;
    }
    res = await checkFileName(openParam.value?.checkName);
  }
  // 设置回调并执行
  if (
    openParam.value?.callback &&
    typeof openParam.value?.callback === 'function'
  ) {
    openParam.value?.callback({ path: currentPath.value, res });
  } else {
    emits('confirm', {
      name: openParam.value?.checkName,
      path: currentPath.value,
    });
  }
  if (res.action !== 'close') visible.value = false;
};
const onCancel = () => {
  emits('cancel');
};
// 跳转到指定目录
const onGoto = (path: string) => {
  if (path) {
    loadFolder(path);
    currentPath.value = path;
  }
};

const open = (data: OpenParamProps) => {
  openParam.value = Object.assign({}, data);
  checkName.value = openParam.value?.checkName || '';
  visible.value = true;
  loadFolder(splitChar);
};
defineExpose({
  open,
});
</script>
<template>
  <ElDialog
    v-model="visible"
    :align-center="true"
    :center="true"
    :close-on-click-modal="false"
    :draggable="true"
    :footer="null"
    modal-class="wos-folder-common-dialog"
    width="640"
    @close="onCancel"
  >
    <template #header>
      <div class="dialog-header">
        {{ openParam?.title || '保存文件到指定文件夹' }}
      </div>
    </template>
    <div class="dialog-body">
      <div class="dialog-body--breadcrumb">
        <ElBreadcrumb :separator-icon="ArrowRight">
          <ElBreadcrumbItem @click="onGoto(splitChar)">根目录</ElBreadcrumbItem>
          <ElBreadcrumbItem
            v-for="(item, index) in breadcrumb"
            :key="index"
            :title="item.name"
            @click="onGoto(item.path)"
          >
            {{ item.name }}
          </ElBreadcrumbItem>
        </ElBreadcrumb>
      </div>
      <div class="dialog-body--list small">
        <div class="layout-list">
          <table
            :class="{ 'h-full': list.length === 0 || loading }"
            class="hor-minimalist-b"
          >
            <colgroup>
              <col width="28" />
              <col width="auto" />
              <col width="160" />
              <col width="100" />
            </colgroup>
            <thead>
              <tr>
                <th scope="col"></th>
                <th class="sort" scope="col">
                  <div class="th">名称</div>
                </th>
                <th class="sort" scope="col">
                  <div class="th">修改时间</div>
                </th>
                <th class="sort" scope="col">
                  <div class="th">大小</div>
                </th>
              </tr>
            </thead>
            <tbody v-if="list.length === 0">
              <tr>
                <td colspan="4">
                  <ElEmpty description="此文件夹为空。" />
                </td>
              </tr>
            </tbody>
            <tbody v-else>
              <tr v-for="(item, index) in list" :key="index">
                <td>{{ index + 1 }}</td>
                <td>
                  <div class="title">
                    <Icon
                      :class="item.type === '2' ? 'folder' : 'file'"
                      :icon="item.icon"
                      class="mr-2"
                    />
                    <div class="name" @dblclick="onItemDbClick(item)">
                      {{ item.name }}
                    </div>
                  </div>
                </td>
                <td>
                  {{ dayjs(item.mtime).format('YYYY-MM-DD HH:mm:ss') }}
                </td>
                <td>
                  {{ item.type === '2' ? '' : formatFileSize(item.size) }}
                </td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
    <template #footer>
      <div class="dialog-footer flex items-center justify-between">
        <div class="flex items-center gap-2">
          <ElButton size="small" @click="onNewFolder">新建文件夹</ElButton>
          <ElDivider direction="vertical" />
          <ElInput v-model="checkName" size="small">
            <template #prepend> 保存名称 </template>
          </ElInput>
        </div>
        <ElButton size="small" type="primary" @click="onConfirm">
          确定
        </ElButton>
      </div>
    </template>
  </ElDialog>
</template>

<style lang="scss">
@import url('./index.scss');
</style>
